#include "StdAfx.h"
#include "TString.h"
#include "Stdlib.h"


TString::TString() : m_pstr(m_szBuffer)
{
   m_szBuffer[0] = '\0';
}

TString::TString(const TCHAR ch) : m_pstr(m_szBuffer)
{
   m_szBuffer[0] = ch;
   m_szBuffer[1] = '\0';
}

TString::TString(LPCTSTR lpsz, int nLen) : m_pstr(m_szBuffer)
{      
   ASSERT(!::IsBadStringPtr(lpsz,-1) || lpsz==NULL);
   Assign(lpsz, nLen);
}

TString::TString(const TString& src) : m_pstr(m_szBuffer)
{
   Assign(src.m_pstr);
}

TString::~TString()
{
   if( m_pstr != m_szBuffer ) free(m_pstr);
}

TString TString::RES(UINT nRes)
{
   HINSTANCE hInstance = GetModuleHandle(NULL);
   if ( NULL == hInstance ) return _T("");

   TCHAR szBuffer[256];
   int cchLen = ::LoadString(hInstance, nRes, szBuffer, lengthof(szBuffer) - 1);
   ASSERT(cchLen>0);
   szBuffer[cchLen] = '\0';
   return szBuffer;
}

int TString::GetLength() const
{ 
   return (int) _tcslen(m_pstr); 
}

TString::operator LPCTSTR() const 
{ 
   return m_pstr; 
}

void TString::Append(LPCTSTR pstr)
{
   int nNewLength = GetLength() + (int) _tcslen(pstr);
   if( nNewLength >= MAX_LOCAL_STRING_LEN ) {
      if( m_pstr == m_szBuffer ) {
         m_pstr = static_cast<LPTSTR>(malloc((nNewLength + 1) * sizeof(TCHAR)));
         _tcscpy(m_pstr, m_szBuffer);
         _tcscat(m_pstr, pstr);
      }
      else {
         m_pstr = static_cast<LPTSTR>(realloc(m_pstr, (nNewLength + 1) * sizeof(TCHAR)));
         _tcscat(m_pstr, pstr);
      }
   }
   else {
      if( m_pstr != m_szBuffer ) {
         free(m_pstr);
         m_pstr = m_szBuffer;
      }
      _tcscat(m_szBuffer, pstr);
   }
}

void TString::Assign(LPCTSTR pstr, int cchMax)
{
   if( pstr == NULL ) pstr = _T("");
   cchMax = (cchMax < 0 ? (int) _tcslen(pstr) : cchMax);
   if( cchMax < MAX_LOCAL_STRING_LEN ) {
      if( m_pstr != m_szBuffer ) {
         free(m_pstr);
         m_pstr = m_szBuffer;
      }
   }
   else if( cchMax > GetLength() || m_pstr == m_szBuffer ) {
      if( m_pstr == m_szBuffer ) m_pstr = NULL;
      m_pstr = static_cast<LPTSTR>(realloc(m_pstr, (cchMax + 1) * sizeof(TCHAR)));
   }
   _tcsncpy(m_pstr, pstr, cchMax);
   m_pstr[cchMax] = '\0';
}

bool TString::IsEmpty() const 
{ 
   return m_pstr[0] == '\0'; 
}

void TString::Empty() 
{ 
   if( m_pstr != m_szBuffer ) free(m_pstr);
   m_pstr = m_szBuffer;
   m_szBuffer[0] = '\0'; 
}

LPCTSTR TString::GetData()
{
   return m_pstr;
}

TCHAR TString::GetAt(int nIndex) const
{
   return m_pstr[nIndex];
}

TCHAR TString::operator[] (int nIndex) const
{ 
   return m_pstr[nIndex];
}   

const TString& TString::operator=(const TString& src)
{      
   Assign(src);
   return *this;
}

const TString& TString::operator=(LPCTSTR lpStr)
{      
   ASSERT(!::IsBadStringPtr(lpStr,-1));
   Assign(lpStr);
   return *this;
}

#ifndef _UNICODE

const TString& TString::operator=(LPCWSTR lpwStr)
{      
   ASSERT(!::IsBadStringPtrW(lpwStr,-1));
   int cchStr = ((int) wcslen(lpwStr) * 2) + 1;
   LPSTR pstr = (LPSTR) _alloca(cchStr);
   if( pstr != NULL ) ::WideCharToMultiByte(::GetACP(), 0, lpwStr, -1, pstr, cchStr, NULL, NULL);
   Assign(pstr);
   return *this;
}

#endif // _UNICODE

const TString& TString::operator=(const TCHAR ch)
{
   Empty();
   m_szBuffer[0] = ch;
   m_szBuffer[1] = '\0';
   return *this;
}

TString TString::operator+(const TString& src)
{
   Append(src);
   return *this;
}

TString TString::operator+(LPCTSTR lpStr)
{
   ASSERT(!::IsBadStringPtr(lpStr,-1));
   Append(lpStr);
   return *this;
}

const TString& TString::operator+=(const TString& src)
{      
   Append(src);
   return *this;
}

const TString& TString::operator+=(LPCTSTR lpStr)
{      
   ASSERT(!::IsBadStringPtr(lpStr,-1));
   Append(lpStr);
   return *this;
}

const TString& TString::operator+=(const TCHAR ch)
{      
   TCHAR str[] = { ch, '\0' };
   Append(str);
   return *this;
}

bool TString::operator == (LPCTSTR str) const { return (Compare(str) == 0); };
bool TString::operator != (LPCTSTR str) const { return (Compare(str) != 0); };
bool TString::operator <= (LPCTSTR str) const { return (Compare(str) <= 0); };
bool TString::operator <  (LPCTSTR str) const { return (Compare(str) <  0); };
bool TString::operator >= (LPCTSTR str) const { return (Compare(str) >= 0); };
bool TString::operator >  (LPCTSTR str) const { return (Compare(str) >  0); };

void TString::SetAt(int nIndex, TCHAR ch)
{
   ASSERT(nIndex>=0 && nIndex<GetLength());
   m_pstr[nIndex] = ch;
}

int TString::Compare(LPCTSTR lpsz) const 
{ 
   return _tcscmp(m_pstr, lpsz); 
}

int TString::CompareNoCase(LPCTSTR lpsz) const 
{ 
   return _tcsicmp(m_pstr, lpsz); 
}

void TString::MakeUpper() 
{ 
   _tcsupr(m_pstr); 
}

void TString::MakeLower() 
{ 
   _tcslwr(m_pstr); 
}

TString TString::Left(int iLength) const
{
   if( iLength < 0 ) iLength = 0;
   if( iLength > GetLength() ) iLength = GetLength();
   return TString(m_pstr, iLength);
}

TString TString::Mid(int iPos, int iLength) const
{
   if( iLength < 0 ) iLength = GetLength() - iPos;
   if( iPos + iLength > GetLength() ) iLength = GetLength() - iPos;
   if( iLength <= 0 ) return TString();
   return TString(m_pstr + iPos, iLength);
}

TString TString::Right(int iLength) const
{
   int iPos = GetLength() - iLength;
   if( iPos < 0 ) {
      iPos = 0;
      iLength = GetLength();
   }
   return TString(m_pstr + iPos, iLength);
}

int TString::Find(TCHAR ch, int iPos /*= 0*/) const
{
   ASSERT(iPos>=0 && iPos<=GetLength());
   if( iPos != 0 && (iPos < 0 || iPos >= GetLength()) ) return -1;
   LPCTSTR p = _tcschr(m_pstr + iPos, ch);
   if( p == NULL ) return -1;
   return p - m_pstr;
}

int TString::Find(LPCTSTR pstrSub, int iPos /*= 0*/) const
{
   ASSERT(!::IsBadStringPtr(pstrSub,-1));
   ASSERT(iPos>=0 && iPos<=GetLength());
   if( iPos != 0 && (iPos < 0 || iPos > GetLength()) ) return -1;
   LPCTSTR p = _tcsstr(m_pstr + iPos, pstrSub);
   if( p == NULL ) return -1;
   return p - m_pstr;
}

int TString::ReverseFind(TCHAR ch) const
{
   LPCTSTR p = _tcsrchr(m_pstr, ch);
   if( p == NULL ) return -1;
   return p - m_pstr;
}

int TString::Replace(LPCTSTR pstrFrom, LPCTSTR pstrTo)
{
   TString sTemp;
   int nCount = 0;
   int iPos = Find(pstrFrom);
   if( iPos < 0 ) return 0;
   int cchFrom = (int) _tcslen(pstrFrom);
   int cchTo = (int) _tcslen(pstrTo);
   while( iPos >= 0 ) {
      sTemp = Left(iPos);
      sTemp += pstrTo;
      sTemp += Mid(iPos + cchFrom);
      Assign(sTemp);
      iPos = Find(pstrFrom, iPos + cchTo);
      nCount++;
   }
   return nCount;
}

int TString::Format(LPCTSTR pstrFormat, ...)
{
   TString sFormat = pstrFormat;
   // Do ordinary printf replacements
   // NOTE: Documented max-length of wvsprintf() is 1024
   TCHAR szBuffer[1025] = { 0 };
   va_list argList;
   va_start(argList, pstrFormat);
   int iRet = ::wvsprintf(szBuffer, sFormat, argList);
   va_end(argList);
   Assign(szBuffer);
   return iRet;
}
